#include "cgzCHttpC.h"
#include "cgzCLua.h"
#include "cgzCThreadPool.h"
#include <cpprest/json.h>
#include <lua.hpp> // 确保你已经安装了 Lua 的开发包

// 将 json::value 转换为 Lua 表
void cgzCLua::json2table(const web::json::value &jsonValue)
{
    // 创建一个新的 Lua 表
    lua_cgz_newt(L);

    // 遍历 json::value
    if (jsonValue.is_object())
    {
        for (const auto &item : jsonValue.as_object())
        {
            const auto &key = item.first;
            const auto &value = item.second;

            // 将键转换为 Lua 字符串
            lua_pushstring(L, key.c_str());

            // 根据 json 值的类型将其推入 Lua 表
            if (value.is_string())
            {
                lua_pushstring(L, value.as_string().c_str());
            }
            else if (value.is_number())
            {
                lua_pushnumber(L, value.as_double());
            }
            else if (value.is_boolean())
            {
                lua_pushboolean(L, value.as_bool());
            }
            else if (value.is_array())
            {
                auto& valArray = value.as_array();
                lua_cgz_newa(L,valArray.size());
                // 处理数组
                size_t index = 1; // Lua 数组从 1 开始
                for (const auto &arrayItem : valArray)
                {
                    // 根据数组项的类型将其推入 Lua 表
                    if (arrayItem.is_string())
                    {
                        lua_pushstring(L, arrayItem.as_string().c_str());
                    }
                    else if (arrayItem.is_number())
                    {
                        lua_pushnumber(L, arrayItem.as_double());
                    }
                    else if (arrayItem.is_boolean())
                    {
                        lua_pushboolean(L, arrayItem.as_bool());
                    }
                    else if (arrayItem.is_object())
                    {
                        json2table(arrayItem); // 递归处理对象
                    }
                    else
                    {
                        lua_pushnil(L); // 对于其他类型，推入 nil
                    }
                    lua_seti(L, -2, index++); // 使用 lua_seti 设置数组元素，index 从 1 开始
                }
            }
            else if (value.is_object())
            {
                // 递归处理对象
                json2table(value);
            }
            else
            {
                lua_pushnil(L); // 对于其他类型，推入 nil
            }

            // 将键值对设置到 Lua 表中
            lua_settable(L, -3); // -3 表示表在栈中的位置
        }
    }
    else if (jsonValue.is_array())
    {
        // 如果 jsonValue 是数组，处理为 Lua 数组
        size_t index = 1; // Lua 数组从 1 开始
        for (const auto &arrayItem : jsonValue.as_array())
        {
            // 根据数组项的类型将其推入 Lua 表
            if (arrayItem.is_string())
            {
                lua_pushstring(L, arrayItem.as_string().c_str());
            }
            else if (arrayItem.is_number())
            {
                lua_pushnumber(L, arrayItem.as_double());
            }
            else if (arrayItem.is_boolean())
            {
                lua_pushboolean(L, arrayItem.as_bool());
            }
            else if (arrayItem.is_object())
            {
                json2table(arrayItem); // 递归处理对象
            }
            else
            {
                lua_pushnil(L); // 对于其他类型，推入 nil
            }
            lua_seti(L, -2, index++); // 使用 lua_seti 设置数组元素，index 从 1 开始
        }
    }
    else
    {
        cgz_this_error("{}", "Provided json::value is not an object or array.");
    }
}

bool cgzCLua::run(const cgzITask *iTask, cgzCHttpExecC *pnode)
{
    switch (pnode->m_cmd)
    {
    case EHTTP_C::HTTPC_GET:
    {
        ocall(iTask->m_tref, "reply", {pnode->m_cookid, "get", pnode->m_ret});
    }
    break;
    case EHTTP_C::HTTPC_POST:
    {
        ocall(iTask->m_tref, "reply", {pnode->m_cookid, "post", pnode->m_ret});
    }
    break;
    case EHTTP_C::HTTPC_PUT:
    {
        ocall(iTask->m_tref, "reply", {pnode->m_cookid, "put", pnode->m_ret});
    }
    break;
    case EHTTP_C::HTTPC_DELETE:
    {
        ocall(iTask->m_tref, "reply", {pnode->m_cookid, "delete", pnode->m_ret});
    }
    break;
    case EHTTP_C::HTTPC_HEAD:
    {
        ocall(iTask->m_tref, "reply", {pnode->m_cookid, "head", pnode->m_ret});
    }
    break;
    case EHTTP_C::HTTPC_OPTIONS:
    {
        ocall(iTask->m_tref, "reply", {pnode->m_cookid, "options", pnode->m_ret});
    }
    break;
    default:
    {
        cgz_this_error("Unknown HTTP command. task:{}", iTask->getName());
    }
    }
    return true;
}

static int httpc_new(lua_State *L)
{
    // 将其转换为 cgzCLua 指针
    cgzCLua *that = cgzCLua::getThat(L);
    const char *name = lua_tostring(L, 1);
    int tref = luaL_ref(L, LUA_REGISTRYINDEX);
    void *node = malloc(sizeof(cgzCHttpC));
    auto cobj = new (node) cgzCHttpC(that->m_pool, name, that->getId());
    cobj->m_tref = tref;
    return 0;
}

static int httpc_get(lua_State *L)
{
    // 将其转换为 cgzCLua 指针
    cgzCLua *that = cgzCLua::getThat(L);
    long cookid = lua_tointeger(L, 1);
    const char *name = lua_tostring(L, 2);
    const char *url = lua_tostring(L, 3);
    const char *uri = lua_tostring(L, 4);
    const char *body = lua_tostring(L, 5);
    std::map<std::string, std::string> headers;
    int n = lua_gettop(L);
    for (int i = 6; i <= n; i += 2)
    {
        const char *key = lua_tostring(L, i);
        const char *value = lua_tostring(L, i + 1);
        headers[key] = value;
    }
    void *node = malloc(sizeof(cgzCHttpGetC));
    auto ask = new (node) cgzCHttpGetC(cookid, url, uri, headers,body);
    that->regTask(name, ask);
    return 0;
}

static int httpc_post(lua_State *L)
{
    // 将其转换为 cgzCLua 指针
    cgzCLua *that = cgzCLua::getThat(L);
    long cookid = lua_tointeger(L, 1);
    const char *name = lua_tostring(L, 2);
    const char *url = lua_tostring(L, 3);
    const char *uri = lua_tostring(L, 4);
    const char *body = lua_tostring(L, 5);
    std::map<std::string, std::string> headers;
    int n = lua_gettop(L);
    for (int i = 6; i <= n; i += 2)
    {
        const char *key = lua_tostring(L, i);
        const char *value = lua_tostring(L, i + 1);
        headers[key] = value;
    }
    void *node = malloc(sizeof(cgzCHttpPostC));
    auto ask = new (node) cgzCHttpPostC(cookid, url, uri, headers,body);
    that->regTask(name, ask);
    return 0;
}

static int httpc_put(lua_State *L)
{
    // 将其转换为 cgzCLua 指针
    cgzCLua *that = cgzCLua::getThat(L);
    long cookid = lua_tointeger(L, 1);
    const char *name = lua_tostring(L, 2);
    const char *url = lua_tostring(L, 3);
    const char *uri = lua_tostring(L, 4);
    const char *body = lua_tostring(L, 5);
    std::map<std::string, std::string> headers;
    int n = lua_gettop(L);
    for (int i = 6; i <= n; i += 2)
    {
        const char *key = lua_tostring(L, i);
        const char *value = lua_tostring(L, i + 1);
        headers[key] = value;
    }
    void *node = malloc(sizeof(cgzCHttpPutC));
    auto ask = new (node) cgzCHttpPutC(cookid, url, uri, headers,body);
    that->regTask(name, ask);
    return 0;
}

static int httpc_delete(lua_State *L)
{
    // 将其转换为 cgzCLua 指针
    cgzCLua *that = cgzCLua::getThat(L);
    long cookid = lua_tointeger(L, 1);
    const char *name = lua_tostring(L, 2);
    const char *url = lua_tostring(L, 3);
    const char *uri = lua_tostring(L, 4);
    const char *body = lua_tostring(L, 5);
    std::map<std::string, std::string> headers;
    int n = lua_gettop(L);
    for (int i = 6; i <= n; i += 2)
    {
        const char *key = lua_tostring(L, i);
        const char *value = lua_tostring(L, i + 1);
        headers[key] = value;
    }
    void *node = malloc(sizeof(cgzCHttpDeleteC));
    auto ask = new (node) cgzCHttpDeleteC(cookid, url, uri, headers,body);
    that->regTask(name, ask);
    return 0;
}

static int httpc_head(lua_State *L)
{
    // 将其转换为 cgzCLua 指针
    cgzCLua *that = cgzCLua::getThat(L);
    long cookid = lua_tointeger(L, 1);
    const char *name = lua_tostring(L, 2);
    const char *url = lua_tostring(L, 3);
    const char *uri = lua_tostring(L, 4);
    const char *body = lua_tostring(L, 5);
    std::map<std::string, std::string> headers;
    int n = lua_gettop(L);
    for (int i = 6; i <= n; i += 2)
    {
        const char *key = lua_tostring(L, i);
        const char *value = lua_tostring(L, i + 1);
        headers[key] = value;
    }
    void *node = malloc(sizeof(cgzCHttpHeadC));
    auto ask = new (node) cgzCHttpHeadC(cookid, url, uri, headers,body);
    that->regTask(name, ask);
    return 0;
}

static int httpc_options(lua_State *L)
{
    // 将其转换为 cgzCLua 指针
    cgzCLua *that = cgzCLua::getThat(L);
    long cookid = lua_tointeger(L, 1);
    const char *name = lua_tostring(L, 2);
    const char *url = lua_tostring(L, 3);
    const char *uri = lua_tostring(L, 4);
    const char *body = lua_tostring(L, 5);
    std::map<std::string, std::string> headers;
    int n = lua_gettop(L);
    for (int i = 6; i <= n; i += 2)
    {
        const char *key = lua_tostring(L, i);
        const char *value = lua_tostring(L, i + 1);
        headers[key] = value;
    }
    void *node = malloc(sizeof(cgzCHttpOptionsC));
    auto ask = new (node) cgzCHttpOptionsC(cookid, url, uri, headers,body);
    that->regTask(name, ask);
    return 0;
}

int cgzCLua::luaopen_httpC(lua_State *L)
{
    static const luaL_Reg otherlib[] = {
        {"new", httpc_new},
        {"get", httpc_get},
        {"post", httpc_post},
        {"put", httpc_put},
        {"det", httpc_delete},
        {"head", httpc_head},
        {"options", httpc_options},
        {NULL, NULL}};

    luaL_newlib(L, otherlib);
    return 1;
}